package world;


import java.util.HashMap;
import java.util.Observable;
import java.util.Observer;

import datatypes.Coordinate;

import packets.SPacket;
import packets.s2cpackets.S0x05;
import packets.s2cpackets.S0x12;
import packets.s2cpackets.S0x1D;
import packets.s2cpackets.S0x21;
import packets.s2cpackets.S0x28;

import entities.Entity;
import entities.EntityEvent;
import entities.Player;

public final class EntityManager extends WorldStateMonitor implements Observer {

	public EntityManager(WorldState state) {
		super(state);
	}




	private int entitiescounter = 0;
	private HashMap<Integer, Entity> entities =  new HashMap<Integer, Entity>();
	
	private int neweid() {
		int newid = entitiescounter;
		entitiescounter ++;
		return newid;
	}
	
	public Player getNewPlayer(String playername) {
		int neweid = neweid();
		Player newPlayer = new Player(neweid, playername);
		entities.put(neweid, newPlayer);

		newPlayer.addObserver(this);

		return newPlayer;
	}
	
	
	/**
	 * To be called when an entity has to be unloaded
	 */
	public void removeEntity(Entity entity) {
		if(entities.containsKey(entity.geteid())) {
			entities.remove(entity.geteid());
			SPacket p = new S0x1D(entity);
			getWorldState().connectionManager().sendPacketToAll(p);
		}
		
	}
	
	
	
	

	@Override
	public void update(Observable object, Object notification) {
		
		Entity entity = (Entity) object;
		EntityEvent event = (EntityEvent) notification;
		
		if(event == EntityEvent.LOCATIONUPDATED) {
			//inform all players of the locationchange
			informEntitymovement(entity);
			
		} else if(event == EntityEvent.ANIMATIONCHANGED) {
			informEntityAnimation(entity);
			
		} else if(event == EntityEvent.ENTITYACTION) {
			informEntityMetadata(entity);
			
		} else if(event == EntityEvent.SELECTEDITEMCHANGED) {
			informEntityChangedItem(entity);
			
		} else {
			System.out.println("TODO: Unknown entity update: "+notification.toString());
		}
		
	}
	
	
	
	private void informEntityAnimation(Entity entity) {
		SPacket p = new S0x12(entity);
		getWorldState().connectionManager().sendPacketToAllOthers(p, entity);
	}
	
	
	private void informEntityMetadata(Entity entity) {
		System.out.println("GOING TO SEND ENTITYMETADATA");
		SPacket p = new S0x28(entity);		
		System.out.println("INFORMING OTHERS!");
		getWorldState().connectionManager().sendPacketToAll(p);
	}
	
	
	
	private void informEntitymovement(Entity entity) {
		Coordinate oldLocation = entity.getLastLocation();
		Coordinate newLocation = entity.getLocation().toAbsCoordinate();
		
		int dX = newLocation.x - oldLocation.x;
		int dY = newLocation.y - oldLocation.y;
		int dZ = newLocation.z - oldLocation.z;
		
		//relative movement
		SPacket p = new S0x21(entity, (byte) dX, (byte) dY, (byte) dZ);

		
		
//		SPacket p = new SPacket(0x22);
//		p.addInt(entity.geteid());
//		p.addInt((int) newLocation.x);
//		p.addInt((int) newLocation.y);
//		p.addInt((int) newLocation.z);
//		p.add((byte) entity.getYaw());
//		p.add((byte) entity.getPitch());
//		
		
		getWorldState().connectionManager().sendPacketToAllOthers(p, entity);

	}
	
	
	
	
	
	
	
	
	/**
	 * TODO: PLAYERMANAGER ???
	 */
	public void informEntityChangedItem(Entity entity) {
		SPacket p = new S0x05((Player) entity);
		getWorldState().connectionManager().sendPacketToAllOthers(p, entity);
		
	}
}
